<?php
/** @noinspection PhpExpressionResultUnusedInspection */
/** @noinspection PhpSignatureMismatchDuringInheritanceInspection */
/**
 * MineAdmin is committed to providing solutions for quickly building web applications
 * Please view the LICENSE file that was distributed with this source code,
 * For the full copyright and license information.
 * Thank you very much for using MineAdmin.
 *
 * @Author kiki
 * @Link   https://gitee.com/xmo/MineAdmin
 */

declare(strict_types=1);
namespace Mine\Generator;

use App\Setting\Model\SettingGenerateColumns;
use App\Setting\Model\SettingGenerateTables;
use App\System\Model\Debug;
use Hyperf\Utils\Filesystem\Filesystem;
use Mine\Exception\NormalStatusException;
use Mine\Helper\Str;

/**
 * 验证器生成
 * Class RequestGenerator
 * @package Mine\Generator
 */
class RequestGenerator extends MineGenerator implements CodeGenerator
{
    /**
     * @var SettingGenerateTables
     */
    protected SettingGenerateTables $model;

    /**
     * @var string
     */
    protected string $codeContent;

    /**
     * @var Filesystem
     */
    protected Filesystem $filesystem;

    /**
     * @var array
     */
    protected array $columns;

    protected string $scenes = '';

    protected string $message = '';

    protected string $createScenes = '';

    protected string $updateScenes = '';

    /**
     * 设置生成信息
     * @param SettingGenerateTables $model
     * @return RequestGenerator
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function setGenInfo(SettingGenerateTables $model): RequestGenerator
    {
        $this->model = $model;
        $this->filesystem = make(Filesystem::class);
        if (empty($model->module_name) || empty($model->menu_name)) {
            throw new NormalStatusException(t('setting.gen_code_edit'));
        }
        $this->setNamespace($this->model->namespace);

        $this->columns = SettingGenerateColumns::query()
            ->where('table_id', $model->id)
//            ->where('is_insert', '1')
//            ->orWhere('is_edit', '1')
//            ->where('is_required', '1')
            ->orderByDesc('sort')
            ->get([ '*' ])->toArray();
//        Debug::info($this->columns);
//        Debug::info($model->id);

        return $this->placeholderReplace();
    }

    /**
     * 生成代码
     */
    public function generator(): void
    {
        $module = Str::title($this->model->module_name);
        if ($this->model->generate_type == '0') {
            $path = BASE_PATH . "/runtime/generate/php/app/{$module}/Request/";
        } else {
            $path = BASE_PATH . "/app/{$module}/Request/";
        }
        $this->filesystem->exists($path) || $this->filesystem->makeDirectory($path, 0755, true, true);
        $this->filesystem->put($path . "{$this->getClassName()}.php", $this->replace()->getCodeContent());
    }

    /**
     * 预览代码
     */
    public function preview(): string
    {
        return $this->replace()->getCodeContent();
    }

    /**
     * 获取模板地址
     * @return string
     */
    protected function getTemplatePath(): string
    {
        return $this->getStubDir() . '/Request/main.stub';
    }

    /**
     * 读取模板内容
     * @return string
     */
    protected function readTemplate(): string
    {
        return $this->filesystem->sharedGet($this->getTemplatePath());
    }

    /**
     * 占位符替换
     */
    protected function placeholderReplace(): RequestGenerator
    {
        $this->setCodeContent(str_replace(
            $this->getPlaceHolderContent(),
            $this->getReplaceContent(),
            $this->readTemplate()
        ));

        return $this;
    }

    /**
     * 获取要替换的占位符
     */
    protected function getPlaceHolderContent(): array
    {
        return [
            '{NAMESPACE}',
            '{COMMENT}',
            '{CLASS_NAME}',
            '{RULES}',
            '{MESSAGE}',
            '{SCENES}',
            '{CREATE_SCENES}',
            '{UPDATE_SCENES}',
        ];
    }

    /**
     * 获取要替换占位符的内容
     */
    protected function getReplaceContent(): array
    {
        return [
            $this->initNamespace(),
            $this->getComment(),
            $this->getClassName(),
            $this->getRules(),
            $this->getMessage(),
            $this->getScenes(),
            $this->getCreateScenes(),
            $this->getUpdateScenes(),
        ];
    }

    /**
     * 初始化命名空间
     * @return string
     */
    protected function initNamespace(): string
    {
        return $this->getNamespace() . "\\Request";
    }

    /**
     * 获取注释
     * @return string
     */
    protected function getComment(): string
    {
        return $this->model->menu_name . '验证数据类';
    }

    /**
     * 获取类名称
     * @return string
     */
    protected function getClassName(): string
    {
        return $this->getBusinessName() . 'Request';
    }

    /**
     * 获取验证数据规则
     * @return string
     */
    protected function getRules(): string
    {
        $query = SettingGenerateColumns::query();
        $columns = $query
            ->where('table_id', $this->model->id)
            ->orderByDesc('sort')
            ->get(['*']);

        $phpContent = '';
        foreach ($columns as $column) {
            $phpContent .= $this->getRuleCode($column);
        }

        return $phpContent;
    }

    /**
     * @param array $column
     * @return string
     */
    protected function getRuleCode($column): string
    {
        $code = '';
        if ($column->is_insert) {
            $this->createScenes .= '\'' . $column->column_name . '\',';
        }
        if ($column->is_edit) {
            $this->updateScenes .= '\'' . $column->column_name . '\',';
        }

        if ($column->is_insert || $column->is_edit) {
            $rules = '';
            if (!empty($column->is_required)) {
                $rule = 'required';
                $this->message .= '\'' . $column->column_name . '.' . $rule . '\'=>\' ' .
                    ($column->column_comment ?: $column->column_name) . '不能为空' . '\',' . PHP_EOL;
                $rules .= $rule;
            }


            if (!empty($column->rules)) {
                if (!is_array($column->rules)) {
                    $column->rules = json_decode($column->rules, true);
                }
                foreach ($column->rules as $v) {
                    $this->getMessageDetail($column, $v);
                    if ($rules) {
                        $rules .= '|'.$v;
                    } else {
                        $rules = $v;
                    }
                }
            }
            if ($rules) {
                $code = <<<php

            // {$column->column_comment} 验证
            '{$column->column_name}' => '{$rules}',
php;
            }
        }

        return $code;
    }

    public function getMessageDetail($column, &$rule)
    {
        if ($rule == 'required') {
            $comment = '必须';
        } elseif (str_contains($rule, 'max')) {
            $max = explode(':', $rule);
            $comment = '最大值为' . $max[1] ?? 100;
        } elseif (str_contains($rule, 'min')) {
            $min = explode(':', $rule);
            $comment = '最小值为' . $min[1] ?? 1;
        } elseif ($rule == 'unique') {
            $rule = $rule . ':' . $this->model->table_name;
            $comment = '已存在';
        } else {
            $comment = '格式错误';
        }

        $this->message .= '\'' . $column->column_name . '.' . $rule . '\'=>\' ' .
            ($column->column_comment ?: $column->column_name) . $comment . '\',' . PHP_EOL;
    }

    public function getMessage(): string
    {
        return $this->message;
    }

    public function getScenes(): string
    {
        return $this->scenes;
    }

    public function getCreateScenes(): string
    {
        return $this->createScenes;
    }

    public function getUpdateScenes(): string
    {
        return $this->updateScenes;
    }

    /**
     * @return string
     */
    protected function getAttributes(): string
    {
        $phpCode = '';
        $path = $this->getStubDir() . '/Request/attribute.stub';
        foreach ($this->columns as $column) {
            $phpCode .= $this->getAttributeCode($column);
        }
        return str_replace('{LIST}', $phpCode, $this->filesystem->sharedGet($path));
    }

    /**
     * @param array $column
     * @return string
     */
    protected function getAttributeCode(array &$column): string
    {
        $space = '            ';
        return sprintf(
            "%s'%s' => '%s',\n", $space, $column['column_name'], $column['column_comment']
        );
    }

    /**
     * 获取业务名称
     * @return string
     */
    public function getBusinessName(): string
    {
        return Str::studly(str_replace(env('DB_PREFIX'), '', $this->model->table_name));
    }

    /**
     * 设置代码内容
     * @param string $content
     */
    public function setCodeContent(string $content)
    {
        $this->codeContent = $content;
    }

    /**
     * 获取代码内容
     * @return string
     */
    public function getCodeContent(): string
    {
        return $this->codeContent;
    }

}